本文为您详细介绍呼叫中心SDK前端接入流程。
在线体验
如果您已经有SaaS工作台的账号,您可以在线体验,并且完全可以按照这个Demo的方式进行接入。
接入热线SDK
所有使用${version}
的地方,需要替换为真实的版本号。详细记录信息,请参见热线SDK更新记录。
- 使用非定制UI接入
- 如果您不需要定制自己的UI,并且您是React体系的项目接入,只需添加以下CDN的资源:
<link rel="stylesheet" href="//at.alicdn.com/t/font_1263869_rz6l63j0yrp.css"/> <link rel="stylesheet" href="//g.alicdn.com/code/lib/antd/4.x.x/antd.min.css"/> <link rel="stylesheet" href="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.css"/> <script src="//g.alicdn.com/code/lib/antd/4.x.x/antd.min.js"></script> <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.js"></script>
注意 请确保您的项目中已经有React、ReactDOM、antd的CDN资源,其中antd的版本建议使用4.x系列。 - 因为构建出的是标准的UMD资源,所以现在可以按照以下方式接入:
window.HotlineClientUi.renderClient( domContainer, // 比如 document.querySelector('#root'),可以替换为任何你想插入的DOM节点。 props, );
- 如果您使用了webpack,还可以使用以下方式接入:
// webpack.config.js module.exports = { //... externals: { HotlineClient: 'HotlineClientUi' } }; // in your app or component import { HotlineClientUI } from 'HotlineClient'; window.HotlineClientUi.renderClient( domContainer, // 比如 document.querySelector('#root'),可以替换为任何你想插入的DOM节点。 props, )
上述所有入参的props的内容,请参见HotlineClientUIProps。
- 如果您不需要定制自己的UI,并且您是React体系的项目接入,只需添加以下CDN的资源:
- 使用定制UI接入
如果您需要定制自己的UI风格,或者需要定制其他UI框架下的组件(比如VUE),可以按照下面的方式来实现:
- 引入以下资源:
<script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-fuyun/index.js"></script>
- 在自己的代码中创建一个HotlineClient的实例:
const { FuYunHotlineClient } = window.HotlineClientFuyun; const client = new FuYunHotlineClient(config);
- 如果您是React体系的项目但是需要定制UI,我们也提供了hooks供您使用:
// 需要在cdn中添加 <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.js"></script> const { useClient } = window.HotlineClientUi; const { client, // HotlineClient 实例 enableState, // EnableState 使能状态 agentContext, // AgentContext callContext, // CallContext checkIn, // 上班签入,可以直接调用 handleAnswerCall, // 接电话 handleDial, // 拨电话 } = useClient(props);
其中props的内容请参考HotlineClientUIProps介绍,EnableState内容请参考EnableState。
- 引入以下资源:
- 不需要UI接入如果您不需要UI,直接使用API的形式调用,我们也提供了一个扁平化API的版本,只需要引入下面这个CDN地址:
使用方式:<script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-api/index.js"></script>
const getHotlineClientSDK = window.HotlineClientApi.default; // config: HotlineClientInitConfig const SDK = getHotlineClientSDK(config); console.log(SDK.client); // 获取client。 console.log(SDK.agent); // 获取agent。 onsole.log(SDK.call); // 获取call。 console.log(SDK.enableState); //获取使能状态。 // 上班签入。 SDK.agentCheckin(); // 下班签出。 SDK.agentCheckout(); // 切空闲。 SDK.agentCheckReady(); // 切小休。 SDK.agentCheckRestful(); //外呼。 SDK.dial(calleePhoneNumber: string, callerPhoneNumber?: string); // 接电话 SDK.answer(); // 电话保持。 SDK.hold(); // 电话取回。 SDK.retrieve(); // 电话转交。 SDK.deflect(identifier: DeflectionIdentifier); // 电话挂断。 SDK.hangUp(); // 释放资源。 SDK.dispose();
因为状态机是维护在后端的,除了由于没有client、agent或者call导致的报错外(比如没有通话直接调挂断),其余的动作都需要用户根据enableState当前的状态判断是否可以发起,比如发起外呼:当前如果外呼是否可以发起,API本身不会拦截,应该由状态进行拦截。
SDK接入常见问题
- 怎么订阅事件?热线中基本上每一个动作(比如状态切换、电话状态变更等)都会对应一些事件,为了保证所有后端的事件都完整的传递给上层应用,我们在HotlineClient的实例上提供了完整的事件监听功能,您可以按照这样的方式从client上发起监听:
client.on('eventName', (data: EventData) => {})
其中eventName可以是HotlineSystemEvents和HotlineCustomEvents中任意的一个key,正如命名所指,HotlineSystemEvents推送的都是后端直接给到的事件信息,而HotlineCustomEvents是SDK系统中自己触发的事件。
目前所有的EventData都是HotlineSocketEventData。
- 使用过程中会不会有环境问题?
会的,目前我们只支持Chrome浏览器64版本以上的环境,我们提供了完整的环境检测工具,包括网络检测、麦克风检测和远端音频播放流程检测。
- 以UI形式接入环境检测工具首先,一定需要以带UI的形式使用,然后加入下面的2个CDN:
现在你只需要将openCheckTool设置为true即可。<link rel="stylesheet" href="//g.alicdn.com/hotline-client/hotline-client-sdk/1.0.1/hotline-client-check-tools/index.css"/> <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/1.0.1/hotline-client-check-tools/index.js"></script>
- 是否可以用npm的形式接入?
考虑到一些依赖需要单独处理的问题,建议使用CDN的形式接入。
术语表
术语详细说明,请参见下表:
术语 | 说明 |
---|---|
Client | 即HotlineClient的实例,可以通过create的方式获取,如果直接以UI形式接入,可以通过onClientOnline回调的方式获取。 |
Agent | 即AgentContext的实例,client调用login之后可以拿到,如果以UI形式接入,可以通过onAgentOnline回调的方式获取。 |
Call | 即CallContext的实例,agent调用dial(外呼)或者振铃的时候,可以从几个特殊事件中可以获取到。
|
EnableState | 状态使能类表示在当前的坐席状态下是否允许一些操作的使用,比如在一通话务中,是否可以挂断,是否可以转接等等完全由这个“使能类”来定义,类型定义,请参见:HotlineClientEnableState。 |
类型定义
- Client相关
- HotlineClient
interface HotlineClient { /** * 获取此热线客户端的上下文对象。 */ readonly context: HotlineClientContext; /** * 发起登录。 * * {@return 一个坐席上下文对象}。 */ login(): Promise<AgentContext>; /** * 更新token。 */ updateToken(token: string): void; }
- FuYunHotlineClient
class FuYunHotlineClient implements HotlineClient { /** * ... */ }
- HotlineClientContext
/** * 表示热线 client 的上下文对象 */ export interface HotlineClientContext { /** * 获取此 client 上的配置信息。 */ readonly config: HotlineClientInitConfig; /** * 获取此 client 上的热线服务。 */ readonly hotlineService: HotlineService; }
- HotlineClientInitConfig
/** * 提供 {@link HotlineClient} 初始化参数的描述。 */ export interface HotlineClientInitConfig { instanceId: string; // 实例 id token: string; // token }
- HotlineClientUIProps
/** * HotlineClientUIProps 定义。 */ export type HotlineClientUIProps = { /** * 初始化 Client 需要的参数。 */ config?: HotlineClientInitConfig; /** * 是否支持拖拽。默认为 false。 */ draggable?: boolean; /** * 拖拽相关的配置。具体可以参考 https://www.n****.com/package/react-draggable * 的 DraggableProps */ draggableProps?: Partial<DraggableProps>; /** * 是否打开检测工具。默认是关闭的。 */ openCheckTool?: boolean; /** * 电话号码是否加密,(脱敏),默认是 false。 */ isPhoneNumberEncrypted?: boolean; onClientOnline?: (client: HotlineClient) => void; onAgentOnline?: (agent: AgentContext) => void; onCallContextChange?: (callContext: CallContext) => void; onLoginError?: (error: Error) => void; };
- HotlineClientEnableState
export interface HotlineClientEnableState { /** * 状态。 */ status: AgentStatus; /** * 可签出。 */ checkoutEnable: boolean; /** * 可签入。 */ checkinEnable: boolean; /** * 可空闲。(继续工作) */ readyEnable: boolean; /** * 可小休。 */ breakEnable: boolean; /** * 可培训。 */ trainEnable: boolean; /** * 可接电话。 */ callAnswerEnable: boolean; /** * 可挂电话。 */ callHangupEnable: boolean; /** * 可拨号。 */ callDialEnable: boolean; /** * 电话可保持。 */ callHoldEnable: boolean; /** * 电话可取回。 * * 保持 + 转接。 */ callRetrieveEnable: boolean; /** * 电话可转接。 */ callDeflectEnable: boolean; }
- HotlineClient
- Agent相关AgentContext
/** * 表示坐席的接口定义。 */ export interface AgentContext extends Disposable { /** * 坐席发起签入。 */ checkIn(): Promise<unknown>; /** * 坐席发起签出。 */ checkOut(): Promise<unknown>; /** * 坐席发起小休。 */ doRest(): Promise<unknown>; /** * 坐席切到在线。 */ checkReady(): Promise<unknown>; /** * 坐席发起拨号。 * @param calleePhoneNumber 被叫号码。 * @param callerPhoneNumber 主叫号码。 */ dial(calleePhoneNumber: string, callerPhoneNumber?: string): Promise<CallContext>; /** * 坐席接电话。 * @param params 接电话需要的身份信息。 */ answer(params?: CallIdentity): Promise<unknow>; }
- Call相关
- CallContext
/** * 表示通话上下文的结构体。 */ export interface CallContext extends EventEmitter<HotlineConnectionEvents>, Disposable { /** * 获取此通话的标识信息。 */ readonly identity: CallIdentity; /** * 获取此通话的方向。 */ readonly callDirection: CallDirection; /** * 获取此通话的呼叫方身份。 */ readonly caller: CallerIdentity; /** * 获取此通话的被呼叫方身份。 */ readonly callee: CallerIdentity; /** * 挂断此通话。 */ hangUp(): Promise<unknown>; /** * 转接此通话。 * @param identifier 转接需要的标识符。 * * 根据 DeflectionIdentifier 的 deflectionType 来确认是否需要返回一个可取回的通话。 */ deflect(identifier: DeflectionIdentifier): void; /** * 保持此通话。 */ hold(): Promise<unknown>; /** * 表示取回此通话。 */ retrieve(): Promise<unknown>; }
- CallIdentity
/** * 表示通话身份的结构体。 */ export interface CallIdentity { /** * 获取此通话的 acId。 */ readonly acId: string; /** * 获取此通话的连接 Id。 */ readonly connId: string; /** * 获取此通话被保持时的连接 Id。 */ readonly holdConnId?: string; /** * 获取此通话的 jobId。 */ readonly jobId: string; }
- CallDirection
/** * 表示通话方向的枚举,如呼入或呼出。 */ export enum CallDirection { /** * 表示呼入。 */ Incoming, /** * 表示呼出。 */ Outgoing, }
- CallContext
- Event事件相关
- HotlineSystemEvents
/** * 后端推送的事件。 */ export interface HotlineSystemEvents<EventData> { AgentCheckin: (data: EventData) => void; // 坐席签入 AgentReady: (data: EventData) => void; // 坐席进入空闲(在线)状态 AgentCallDialOut: (data: EventData) => void; // 坐席正在外呼事件 AgentJoinChannel: (data: EventData) => void; // RTC 建立,坐席加入聊天 AgentLeaveChannel: (data: EventData) => void; // RTC 断开,坐席离开聊天 AgentCheckout: (data: EventData) => void; // 坐席签出事件 AgentBreak: (data: EventData) => void; // 坐席小休事件 AgentAcw: (data: EventData) => void; // 坐席进入话后处理事件 AgentRinging: (data: EventData) => void; // 坐席振铃 // AgentCallRelease: (data: EventData) => void; // 通话结束,商业化场景暂时没有 AgentCallAnswerRequest: (data: EventData) => void; // FIXME: 待确认 AgentCallInboundEstablish: (data: EventData) => void; // 入呼通道建立事件 AgentCallOutBoundEstablish: (data: EventData) => void; // 外呼通道建立事件 AgentCallConferenceWaitAnswer: (data: EventData) => void; // 双步转等待第三方接听事件 AgentCallHeld: (data: EventData) => void; // 通话保持事件 }
- HotlineCustomEvents
export interface HotlineCustomEvents<EventData> { AgentStatusChange: (data: EventData) => void; // 坐席状态变更事件 EnableStateChange: (data: HotlineClientEnableState) => void;// 使能类变更事件。 CallVoiceText: (data: EventData) => void; // 通话语音文本事件 AgentReconnect: (status: AgentStatus) => void; // 坐席断线重连消息。 AgentCallReconnect: (status: AgentStatus, callContext: CallContext) => void; // 通话断线重连消息。 BeforeCallHold: () => void; // 电话保持动作被触发前触发。 AfterCallHold: () => void; // 电话保持成功后触发。 BeforeCallDeflect: () => void; // 电话转交动作被触发前触发。 BeforeCallHangup: () => void; // 电话挂断动作被触发前触发。 AfterCallHangup: () => void; // 电话挂断成功后触发。 BeforeCallAnswer: () => void; // 电话接起动作被触发前触发。 AfterCallAnswer: () => void; // 电话接起成功后触发。 BeforeCallDial: () => void; // 电话拨号动作被触发前触发。 AfterCallDial: () => void; // 电话拨号成功后触发。 BeforeCallRetrieve: () => void; // 电话取回动作被触发前触发。 AfterCallRetrieve: () => void; // 电话取回成功后触发。 UnHandleEvent: (data: EventData) => void; // 异常兜底。 TokenExpired: () => void; // Token过期事件。 SystemCallRinging: (call: CallContext) => void; // 带话务上下文的系统振铃事件。 SystemCallDialOut: (call: CallContext) => void; // 带话务上下文的系统外呼事件。 }
- HotlineSocketEventData
/** * 热线 socket 消息体 */ export interface HotlineSocketEventData { eventName: string; buId?: number; departmentId?: number; enumIconType?: string; enumSceneType?: string; gmtCreate?: number; head: HotlineSocketHeadData; isPersistent?: boolean; sceneType?: string; senderId?: number; senderType?: string; userId?: number; uuid?: string; content: string; } export interface HotlineSocketHeadData { agentBasicCode?: AgentBasicCode; agentBasicDesc?: string; agentCallCode?: AgentCallCode; agentCallDesc?: string; aid?: string; appName?: string; cmd?: string; departmentId?: string; mid?: string; name?: string; supportNewFunction?: string; time?: string; tk?: string; xspaceHotline?: string; jobId?: string; connId?: string; holdConnId?: string; acid?: string; dnis?: string; ani?: string; }
- HotlineSystemEvents
- 其他类型说明DeflectionIdentifier
export interface DeflectionIdentifier { isSingleTransfer?: boolean; // true 是单步转,false 是双步转,默认是 true isTransferSkillGroup?: boolean; // 是否转接给技能组。 isTransferPhone?: boolean; // 是否转接给电话号。 caller?: string; // 转接到电话的主叫号码。 callee?: string; // 转接到电话的被叫号码。 skillGroupId?: string; // 转接的技能组 id }